package top.surgeqi.security.jwt.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import top.surgeqi.security.jwt.bean.JwtDTO;
import top.surgeqi.security.jwt.contants.AuthConstants;
import top.surgeqi.security.jwt.handler.AuthenticationExceptionHandler;

/**
 * <p><em>Created by qipp on 2020/7/2 15:01</em></p>
 * SecurityJwt 自动配置类
 *
 * @author <a href="https://gitee.com/qipengpai">qipp</a>
 * @since 2.0.1
 */
@Slf4j
@Configuration
public class SurgeSecurityJwtAutoConfiguration {

    /**
     * 令牌相关操作Service
     */
    private final JwtTokenService jwtTokenService;

    /**
     * springmvc启动时自动装配json处理类
     */
    private final ObjectMapper objectMapper;

    public SurgeSecurityJwtAutoConfiguration(JwtTokenService jwtTokenService, ObjectMapper objectMapper) {
        this.jwtTokenService = jwtTokenService;
        this.objectMapper = objectMapper;
    }

    /**
     * 默认通用认证异常处理器
     *
     * @return top.surgeqi.security.jwt.handler.AuthenticationExceptionHandler 默认通用认证异常处理器
     * @author qipp
     * @date 2020/7/2 15:13
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationExceptionHandler.class)
    public AuthenticationExceptionHandler surgeAuthenticationExceptionHandler() {
        return (request, response, customerAuthenticationException) -> {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(AuthConstants.CONTENT_TYPE);
            // 返回自定义的异常码
            response.getWriter().write(objectMapper.writeValueAsString(
                    ImmutableMap.of(
                            "code", "error",
                            "message", customerAuthenticationException.getMessage())));
            response.getWriter().flush();
            response.getWriter().close();
        };
    }

    /**
     * 默认通用认证成功处理器
     *
     * @return org.springframework.security.web.authentication.AuthenticationSuccessHandler 默认通用认证成功处理器
     * @author qipp
     * @date 2020/7/2 15:42
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationSuccessHandler.class)
    public AuthenticationSuccessHandler surgeAuthenticationSuccessHandler() {
        return (httpServletRequest, httpServletResponse, authentication) -> {
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            // 生成token
            JwtDTO jwtDTO = jwtTokenService.generateToken(userDetails);
            // 返回令牌对象
            httpServletResponse.setStatus(HttpStatus.OK.value());
            httpServletResponse.setContentType(AuthConstants.CONTENT_TYPE);
            // 转换JSON对象并返回
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(jwtDTO));
            httpServletResponse.getWriter().flush();
            httpServletResponse.getWriter().close();
        };
    }


    /**
     * 默认通用认证成功处理器
     *
     * @return org.springframework.security.web.authentication.AuthenticationSuccessHandler 默认通用认证成功处理器
     * @author qipp
     * @date 2020/7/2 15:42
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationEntryPoint.class)
    public AuthenticationEntryPoint surgeAuthenticationEntryPointHandler() {
        return (request, response, authentication) -> {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(AuthConstants.CONTENT_TYPE);
            // 登录过期/用户未登录
            response.getWriter().write(objectMapper.writeValueAsString("登录过期/用户未登录"));
            response.getWriter().flush();
            response.getWriter().close();
        };
    }


    /**
     * 默认通用认证成功处理器
     *
     * @return org.springframework.security.web.authentication.AuthenticationSuccessHandler 默认通用认证成功处理器
     * @author qipp
     * @date 2020/7/2 15:42
     */
    @Bean
    @ConditionalOnMissingBean(AccessDeniedHandler.class)
    public AccessDeniedHandler surgeAccessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            // 无权限
            log.info("无权限 --->  CustomAccessDeniedHandler ");
            response.setContentType(AuthConstants.CONTENT_TYPE);
            response.getWriter().write(objectMapper.writeValueAsString("无权限"));
            response.getWriter().flush();
            response.getWriter().close();
        };
    }

    /**
     * 默认通用认证成功处理器
     *
     * @return org.springframework.security.web.authentication.AuthenticationSuccessHandler 默认通用认证成功处理器
     * @author qipp
     * @date 2020/7/2 15:42
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationFailureHandler.class)
    public AuthenticationFailureHandler surgeAuthenticationFailureHandler() {
        return (request, response, exception) -> {
            // 返回认证错误与具体认证异常消息
            log.info("loginFailureHandler ---> {}", exception.getMessage());
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(AuthConstants.CONTENT_TYPE);
            response.getWriter().write(objectMapper.writeValueAsString(exception.getMessage()));
            response.getWriter().flush();
            response.getWriter().close();
        };
    }
}
